package com.mijie.homi.api;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.Hashtable;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.mijie.core.StringFilter;
import com.mijie.homi.common.constant.MCKey;
import com.mijie.homi.common.domain.timeline.TimelineEvent;
import com.mijie.homi.common.domain.user.User;
import com.mijie.homi.service.cache.MemcacheService;
import com.mijie.homi.service.mood.MoodService;
import com.mijie.homi.service.timeline.TimelineService;
import com.mijie.homi.service.topic.TopicService;
import com.mijie.homi.service.user.DeviceInfoService;
import com.mijie.homi.service.user.UserExtInfoService;
import com.mijie.homi.service.user.UserService;
import com.mijie.homi.util.ServerHelper;
import com.mijie.util.DateUtil;
import com.mijie.util.Helper;
import com.mijie.util.IOUtil;

@Controller
@RequestMapping("/internal")
public class InternalApi {

	private static Logger logger = Logger.getLogger(InternalApi.class);
	@Autowired
	private UserService userService;
	@Autowired
	private UserExtInfoService extInfoService;
	@Autowired
	private TopicService topicService;
	@Autowired
	private DeviceInfoService deviceInfoService;
	@Autowired
	private MemcacheService mcs;
	@Autowired
	private TimelineService timelineService;
	
	@RequestMapping(value="/push_remind_notify",method=RequestMethod.GET)
	public @ResponseBody void pushRemindNotify(){
//		deviceInfoService.pushRemindNotify();
	}
	
	@RequestMapping(value="/showApi")
	public  @ResponseBody  void showApi(){
		Class<?> clazz = null;
        Method[] methods = null;
        String[] values = null;
        String prefix = "";
        String url = "";
        String requestMethod = "";
        RequestMapping mapping = null;
	        
		ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);
        scanner.addIncludeFilter(new AnnotationTypeFilter(RequestMapping.class));
        for (BeanDefinition beanDefinition : scanner.findCandidateComponents("com")){
			try {
				clazz = Class.forName(beanDefinition.getBeanClassName());
			} catch (ClassNotFoundException e) {
				logger.error(e.getMessage(), e);
			}
			
        	
        	if(clazz.isAnnotationPresent(Controller.class) && clazz.isAnnotationPresent(RequestMapping.class)){
        		mapping = clazz.getAnnotation(RequestMapping.class);
        		if(mapping.value()!=null && mapping.value()[0]!=null && !mapping.value()[0].trim().isEmpty()){
        			prefix = mapping.value()[0].trim();
        		}
        	}
        	
        	methods = clazz.getDeclaredMethods();
        	if(methods!=null){
        		for(Method method : methods){
        			if(!method.isAnnotationPresent(RequestMapping.class)) 
        				continue;
        			mapping = method.getAnnotation(RequestMapping.class);
        			if(mapping.value()!=null && mapping.value()[0]!=null && !mapping.value()[0].trim().isEmpty()){
        				url = mapping.value()[0].trim();
            		}
        			if(mapping.method().length>0){
        				requestMethod = mapping.method()[0].name();
        			}
        			
        			logger.info("###Controller["+clazz.getName()+"] url:"+prefix+url+",method:"+requestMethod);
        		}
        	}
        }
	}
	
	@RequestMapping(value="/makeTimeline",method=RequestMethod.GET)
	public @ResponseBody void makeTimeline() throws Exception{
		List<TimelineEvent> list = new ArrayList<TimelineEvent>();
		Connection conn = null;
		Statement stmt = null;
		TimelineEvent event = null;
		try{
			conn = ServerHelper.getConnection();
			stmt = conn.createStatement();
			ResultSet rs = stmt.executeQuery("select id,userId,createAt from mood");
			while(rs.next()){
				event = new TimelineEvent();
				event.setEventType(TimelineEvent.TYPE_MOOD);
				event.setEventId(rs.getLong("id"));
				event.setUserId(rs.getInt("userId"));
				event.setCreateAt(rs.getTimestamp("createAt").getTime());
				list.add(event);
			}
			rs.close();
			
			rs = stmt.executeQuery("select id,author,createAt from topic");
			while(rs.next()){
				event = new TimelineEvent();
				event.setEventType(TimelineEvent.TYPE_TOPIC);
				event.setEventId(rs.getLong("id"));
				event.setUserId(rs.getInt("author"));
				event.setCreateAt(rs.getTimestamp("createAt").getTime());
				list.add(event);
			}
			rs.close();
		}finally{
			if(stmt!=null) stmt.close();
			if(conn!=null) conn.close();
		}
		
		Collections.sort(list, new Comparator<TimelineEvent>(){
			public int compare(TimelineEvent o1, TimelineEvent o2) {
				if(o1.getCreateAt()>o2.getCreateAt()) return 1;
		        return -1;
			}
		});
		
		logger.info("makeTimeline begin.!");
		makeTimelineWorker(list);
		logger.info("makeTimeline done.!");
	}
	
	@Transactional(rollbackFor={Exception.class})
	private void makeTimelineWorker(List<TimelineEvent> list) throws Exception{
		StringBuilder sb = new StringBuilder();
		int size = 0;
		int counter = 0;
		Connection conn = null;
		Statement stmt = null;
		String prefix = "insert into timeline_1(userId,eventId,eventType,createAt)";
		long st,et = 0;
		try{
			conn = ServerHelper.getConnection();
			stmt = conn.createStatement();
			for(TimelineEvent e : list){
				if(size>0 && size%500==0){
					st = System.currentTimeMillis();
					stmt.execute(prefix+sb.toString());
					et = System.currentTimeMillis();
					size = 0;
					sb.setLength(0);
					counter+=500;
					logger.info("process at "+counter+", import 500 sql spends "+(et-st)+" millis.");
				}
				if(size==0) sb.append(" values");
				else sb.append(",");
				sb.append("(").append(e.getUserId()).append(",").append(e.getEventId()).append(",").append(e.getEventType()).append(",").append(e.getCreateAt()).append(")");
				size++;
			}
			
			if(size!=0){
				st = System.currentTimeMillis();
				stmt.execute(prefix+sb.toString());
				et = System.currentTimeMillis();
				counter+=size;
				logger.info("process at "+counter+", import "+size+" sql spends "+(et-st)+" millis.");
			}
			
			logger.info("################################import done###########################");
			
			st = System.currentTimeMillis();
			stmt.execute("update mood as m right join timeline_1 as t on t.eventId=m.id set m.timelineId=t.id where t.eventType="+TimelineEvent.TYPE_MOOD);
			et = System.currentTimeMillis();
			logger.info("update mood timelineId done.spends "+(et-st)+" millis.");
			
			st = System.currentTimeMillis();
			stmt.execute("update topic as m right join timeline_1 as t on t.eventId=m.id set m.timelineId=t.id where t.eventType="+TimelineEvent.TYPE_TOPIC);
			et = System.currentTimeMillis();
			logger.info("update topic timelineId done.spends "+(et-st)+" millis.");
			
			logger.info("makeTimelineWorker done.");
		}finally{
			if(stmt!=null) stmt.close();
			if(conn!=null) conn.close();
		}
	}
	
	
	@RequestMapping(value="/genFreeIds",method=RequestMethod.GET)
	public @ResponseBody void makeFreeIds(){
		//用户生产一批用户ID,直接到服务器上执行curl  http://localhost:8282/internal/genFreeIds.shtml运行
		new Thread(){
			public void run(){
				try {
					genFreeIds();
				} catch (Exception e) {
					logger.error(e.getMessage(), e);
				}
			}
		}.start();
	}
	
	class ReviewWrapper{
		public Long id;
		public Long targetId;
		public int receiver;
		public String content;
		public int reviewer;
		public Date createAt;
		public int type;
	}
	
	private static Comparator<ReviewWrapper> comparator = new Comparator<ReviewWrapper>(){

		public int compare(ReviewWrapper src, ReviewWrapper target) {
			return src.createAt.after(target.createAt)?1:-1;
		}
		
	};
	
	@RequestMapping(value="/importReview",method=RequestMethod.GET)
	public @ResponseBody void importReview() throws Exception{
		Connection conn = ServerHelper.getConnection();
		Statement commentStmt = null;
		Statement replyStmt = null;
		Statement reviewStmt = null;
		Statement updateStmt = null;
		String[] commentTables = {"moodComment","photoComment","topicOpinionComment"};
		String[] replyTables = {"moodCommentReply","photoCommentReply","topicOpinionCommentReply"};
		String[] reviewTables = {"moodReview","photoReview","topicOpinionReview"};
		
		List<ReviewWrapper> list = new ArrayList<ReviewWrapper>(600);
		Hashtable<Long,Long> targetIdMap = new Hashtable<Long,Long>();
		Hashtable<Long,Integer> reviewIdMap = new Hashtable<Long,Integer>();
		try{
			commentStmt = conn.createStatement();
			replyStmt = conn.createStatement();
			reviewStmt = conn.createStatement();
			updateStmt = conn.createStatement();
			ResultSet commentRs = null;
			ResultSet replyRs = null;
			for(int index=0;index<3;index++){
				list.clear();
				commentStmt.execute("truncate "+reviewTables[index]);
				commentRs = commentStmt.executeQuery("select id,targetId,receiver,content,reviewer,createAt from "+commentTables[index]);
				while(commentRs.next()){
					ReviewWrapper review = new ReviewWrapper();
					review.id = commentRs.getLong("id");
					review.targetId = commentRs.getLong("targetId");
					review.receiver = commentRs.getInt("receiver");
					review.reviewer = commentRs.getInt("reviewer");
					review.content = commentRs.getString("content");
					review.createAt = DateUtil.str2date(commentRs.getString("createAt"), true);
					review.type = 1;
					list.add(review);
					
					targetIdMap.put(review.id, review.targetId);
					
					replyRs = replyStmt.executeQuery("select id,targetId,sender,receiver,content,createAt from "+replyTables[index]+" where targetId="+commentRs.getInt("id"));
					while(replyRs.next()){
						review = new ReviewWrapper();
						review.id = replyRs.getLong("id");
						review.targetId = replyRs.getLong("targetId");
						review.receiver = replyRs.getInt("receiver");
						review.reviewer = replyRs.getInt("sender");
						review.content = replyRs.getString("content");
						review.createAt = DateUtil.str2date(replyRs.getString("createAt"), true);
						review.type = 2;
						list.add(review);
					}
					replyRs.close();
				}
				commentRs.close();
				
				Collections.sort(list, comparator);
				
				ResultSet rs = null;
				for(ReviewWrapper w : list){
					if(w.type==1){
						//旧版评论
						reviewStmt.execute("insert into "+reviewTables[index]+"(eventId,reviewer,receiver,content,createAt) values("+w.targetId+","+w.reviewer+","+w.receiver+",'"+w.content+"','"+DateUtil.date2str(w.createAt, true)+"')");
						rs = reviewStmt.executeQuery("select  LAST_INSERT_ID()");
						rs.next();
						updateStmt.executeUpdate("update "+commentTables[index]+" set reviewId="+rs.getInt(1) +" where id="+w.id);
						reviewIdMap.put(w.id, rs.getInt(1));
						logger.info("put value:"+rs.getInt(1)+" for key:"+w.id+" to reviewIdMap");
					}else{
						if(reviewIdMap.containsKey(w.targetId)){
							reviewStmt.execute("insert into "+reviewTables[index]+"(eventId,referId,rootId,reviewer,receiver,content,createAt) values("+targetIdMap.get(w.targetId)+","+reviewIdMap.get(w.targetId)+","+reviewIdMap.get(w.targetId)+","+w.reviewer+","+w.receiver+",'"+w.content+"','"+DateUtil.date2str(w.createAt, true)+"')");
							rs = reviewStmt.executeQuery("select  LAST_INSERT_ID()");
							rs.next();
							updateStmt.executeUpdate("update "+replyTables[index]+" set reviewId="+rs.getInt(1) +" where id="+w.id);
						}else{
							logger.error("reply[id:"+w.id+"] need comment[id:"+w.targetId+"] but not found.drop this reply.");
						}
					}
				}
				logger.info("========import "+reviewTables[index]+" finish===========");
			}
		}catch(Exception e){
			logger.error(e.getMessage(), e);
		}finally{
			if(updateStmt!=null) updateStmt.close();
			if(reviewStmt!=null) reviewStmt.close();
			if(replyStmt!=null) replyStmt.close();
			if(commentStmt!=null) commentStmt.close();
		}
		logger.info("========importReview done===========");
	}
	
	@RequestMapping(value="/setMoodVisibility",method=RequestMethod.GET)
	public @ResponseBody void setMoodVisibility() throws Exception{
		Connection conn = ServerHelper.getConnection();
		Statement userStmt = null;
		Statement moodStmt = null;
		int index = 0;
		try{
			userStmt = conn.createStatement();
			moodStmt = conn.createStatement();
			ResultSet rs = userStmt.executeQuery("select id from userExtInfo where moodId>0");
			int visibility = 0;
			int userId = 0;
			String moodLocusVisible = null;
			ResultSet privacyRs = null;
			while(rs.next()){
				userId = rs.getInt(1);
				privacyRs  = moodStmt.executeQuery("select moodLocusVisible from privacy where id="+userId);
				if(privacyRs.next()){
					moodLocusVisible = privacyRs.getString(1);
					visibility = 1;
					if(moodLocusVisible.equals("10")){
						visibility = 2;
					}else if(moodLocusVisible.equals("00")){
						visibility = 3;
					}
					moodStmt.execute("update mood set visibility="+visibility+" where userId="+userId);
				}
				index++;
				if(index % 500 == 0)
					logger.info("setMoodVisibility index:"+index);
			}
		}catch(Exception e){
			logger.error(e.getMessage(), e);
		}finally{
			if(moodStmt!=null) moodStmt.close();
			if(userStmt!=null) userStmt.close();
		}
		logger.info("========importLastMood done===========");
	}
	
	@RequestMapping(value="/updateGender",method=RequestMethod.GET)
	public @ResponseBody void updateGender(int userId,int gender) throws Exception{
		userService.updateGender(userId, gender);
	}
	
	@RequestMapping(value="/countPhotoAmount",method=RequestMethod.GET)
	public @ResponseBody void countPhotoAmount() throws Exception{
		Connection conn = ServerHelper.getConnection();
		Statement userStmt = null;
		Statement photoStmt = null;
		try{
			userStmt = conn.createStatement();
			photoStmt = conn.createStatement();
			ResultSet rs = photoStmt.executeQuery("SELECT userId,count(*) FROM photo group by userId");
			while(rs.next()){
				userStmt.executeUpdate("update userExtInfo set numOfPhoto=0 where id="+rs.getInt(1));
				extInfoService.incrNumOfPhoto(rs.getInt(1), rs.getInt(2));
			}
		}catch(Exception e){
			logger.error(e.getMessage(), e);
		}finally{
			if(photoStmt!=null) photoStmt.close();
			if(userStmt!=null) userStmt.close();
		}
		logger.info("========countPhotoAmount done===========");
	}
	
	
	@RequestMapping(value="/countMoodAmount",method=RequestMethod.GET)
	public @ResponseBody void countMoodAmount() throws Exception{
		Connection conn = ServerHelper.getConnection();
		Statement userStmt = null;
		Statement moodStmt = null;
		try{
			userStmt = conn.createStatement();
			moodStmt = conn.createStatement();
			ResultSet rs = moodStmt.executeQuery("SELECT userId,count(*) FROM mood group by userId");
			while(rs.next()){
				userStmt.executeUpdate("update userExtInfo set numOfMood="+rs.getInt(2)+" where id="+rs.getInt(1));
				mcs.delete(MCKey.USER_EXTINFO_BY_ID, String.valueOf(rs.getInt(1)));
			}
		}catch(Exception e){
			logger.error(e.getMessage(), e);
		}finally{
			if(moodStmt!=null) moodStmt.close();
			if(userStmt!=null) userStmt.close();
		}
		logger.info("========countMoodAmount done===========");
	}
	
	
	
	//马甲
	@RequestMapping(value="/genInternalUser",method=RequestMethod.GET)
	public @ResponseBody void genInternalUser(){
		List<Integer> list = new ArrayList<Integer>();
		for(int i=10000;i<100000;i++){
			list.add(i);
		}
		Collections.shuffle(list);
		User user = null;
		List<User> userList = new ArrayList<User>(100);
		for(int i=0;i<list.size();i++){
			user = new User();
			user.setId(list.get(i));
			user.setPasswd("mj"+Helper.genUUID().substring(0, 7));
			userList.add(user);
			if(userList.size()==100){
				logger.info("[index:"+i+"] genInternalUser flush to db.");
				userService.createInternalUser(userList);
				userList.clear();
			}
		}
		if(userList.size()>0){
			userService.createInternalUser(userList);
			userList.clear();
		}
		logger.info("genInternalUser done.");
	}
	
	private  void genFreeIds() throws Exception{
		Connection conn = null;
		Statement stmt = null;
		try{

			int size = 100000;
			int offset = 6899993;
			for(int i=0;i<50;i++){
				conn = ServerHelper.getConnection();
				stmt = conn.createStatement();
				int limit = offset+ size;
				if(limit>Integer.MAX_VALUE) return;
				List<Integer> list = new ArrayList<Integer>(size);
				for(int num=offset;num<limit;num++)
					list.add(num);
				Collections.shuffle(list);
				for(int index=0;index<list.size();index++){
					stmt.addBatch("insert into idBox(id) values("+list.get(index)+")");
					if(index%3000==0){
						stmt.executeBatch();
						stmt.clearBatch();
						logger.info("###genFrreIds loop "+i+", index "+index+" executeBath.");
					}
				}
				stmt.executeBatch();
				stmt.close();
				conn.close();
				offset = limit;
				logger.info("###genFrreIds loop "+i+" done! offset = "+offset);
			}
		}catch(Exception e){
			logger.error(e.getMessage(), e);
		}finally{
			try{
				if(stmt!=null) stmt.close();
				if(conn!=null) conn.close();
			}catch(Exception e){
				logger.error(e.getMessage(), e);
			}
			logger.info("###genFrreIds done!");
		}
	}
	
	@RequestMapping(value="/sensitiveword/reload")
	public @ResponseBody void sensitivewordReload(HttpServletResponse response) {
		logger.info("===========================sensitivewordReload begin===========================");
		File file = StringFilter.getInstanct().getFile();
		if(file!=null){
			ServerHelper.reExportSensitiveWordFromDB(file);
			StringFilter.getInstanct().reload();
		}else{
			logger.info("##sensitivewordReload can't find the files to save");
		}
		response.setStatus(response.SC_NO_CONTENT);
		logger.info("===========================sensitivewordReload done===========================");
	}
	
	//管理后台审核话题
	@RequestMapping(value="/topic/verify",method=RequestMethod.POST)
	public @ResponseBody void topicVerify(int topicId,int pass,String reason,HttpServletResponse response) {
		try {
			topicService.verify(topicId, pass, reason);
			response.setStatus(response.SC_NO_CONTENT);
		} catch (Exception e) {
			response.setStatus(response.SC_INTERNAL_SERVER_ERROR);
		}
		
	}
	
	@RequestMapping(value="/topic/verify/pass_all",method=RequestMethod.POST)
	public @ResponseBody void topicVerifyPassAll(HttpServletRequest request,HttpServletResponse response) throws IOException {
		String idStr = IOUtil.getContent4InputStream(request.getInputStream());
		String[] ids = idStr.split(",");
		if(ids!=null && ids.length>0){
			try {
				for(String id : ids)
					topicService.verify(Integer.parseInt(id), 1, "");
				response.setStatus(response.SC_NO_CONTENT);
			}catch (Exception e) {
				response.setStatus(response.SC_INTERNAL_SERVER_ERROR);
			}
		}
		
	}
	
}
